<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>

<body>
  <script>
    // 一个发布者、多个订阅者

    // 定义发布者抽象类
    class Publisher {
      constructor() {
        this.observer = []
      }

      // 增加订阅者
      add(observer) {
        this.observer.push(observer)
      }

      // 移除订阅者
      remove(observer) {
        this.observer.forEach((item, i) => {
          if (item === observer) {
            this.observer.splice(i, 1)
          }
        })
      }

      // 通知所有订阅者
      notify() {

      }
    }

    // 定义订阅者抽象类
    class Observer {
      constructor() { }

      // 更新
      update() { }
    }

    // 定义发布者具体类：需求文档(prd)类
    class PrdPublisher extends Publisher {
      constructor() {
        super()
        // 初始化需求文档
        this.prdState = null
        this.observer = []
      }

      // 获取当前需求文档状态
      getState() {
        return this.prdState
      }

      // 修改当前需求文档状态
      setState(state) {
        this.prdState = state
        // 文档状态变更，立即通知所有开发者
        this.notify()
      }
    }

    // 定义订阅者具体类：开发者类
    class DeveloperObserver extends Observer {
      constructor() {
        super()
        // 初始化需求文档
        this.prdState = {}
      }

      // 获取需求文档并开始干活
      update(publisher) {
        // 更新需求文档
        this.prdState = publisher.getState()
        this.work()
      }

      // 搬砖方法
      work() {
        // 获取需求文档
        const prd = this.prdState
        console.log('订阅者获取需求文档', prd)
      }
    }

    // 创建订阅者：前端开发李雷
    const liLei = new DeveloperObserver()
    // 创建订阅者：服务端开发小A（sorry。。。起名字真的太难了）
    const A = new DeveloperObserver()
    // 创建订阅者：测试同学小B
    const B = new DeveloperObserver()
    // 创建发布者：韩梅梅
    const hanMeiMei = new PrdPublisher()
    // 需求文档出现了
    const prd = {
      // 具体的需求内容
      a: 1,
      b: 2
    }
    // 添加订阅者
    hanMeiMei.add(liLei)
    hanMeiMei.add(A)
    hanMeiMei.add(B)
    // 韩梅梅发送了需求文档，并@了所有人
    hanMeiMei.setState(prd)
    liLei.update(hanMeiMei) // {a: 1, b: 2}
    // 修改需求文档
    prd.c = 3
    hanMeiMei.setState(prd)
    liLei.update(hanMeiMei) // {a: 1, b: 2, c: 3}
  </script>
</body>

</html>